Repository navigation
fix(declare): bash declaration engine, locals, attributes and set options (105 BashBox cases) - #2597
Merged
Merged
Conversation
Copies (script, stdout) pairs from shipfastlabs/bashbox (MIT) into spec_cases/bash/bashbox-*.test.sh, keeping only cases whose recorded output matches host bash. 624 pass and join the bash comparison gate; 420 are marked TODO skips: real gaps where bashkit differs from bash. Attribution in NOTICE; process in knowledge/operations/testing.md.
Replace the string-splitting arithmetic evaluator with a tokenizer and a precedence-climbing parser that follows bash's expr.c grammar (comma, assignment operators, ternary, short-circuit with noeval, right-assoc `**`, base#digits up to 64, pre/post increment on elements). Errors now behave as in bash: `$((...))` errors print the bash message and abort the rest of the current line (new ControlFlow::Abort / Error::LineAbort); `((...))` and `let` return status 1. The body of a `((...))` command is read raw so `<<=`/`>>` are not lexed as redirects. Unskips the bashbox-arithmetic-array cases and bashbox_declare_a_subshell_ends_with_status_1.
declare/typeset/local/export/readonly now run through one engine (interpreter/declare.rs) with bash's option sets, error messages and declare -p output (quoting, assoc arrays in bash hash order). Locals use shallow binding saved in the call frame: nested functions, unset of a caller's local, declare -g past a local and local -n follow bash. Compound operands stay one CompoundAssignment word part, so keyed elements with quotes or backticks lex as one element and analysis walks substitutions inside them. Readonly assignment and circular namerefs abandon the line as in bash. Unskips 60 bashbox declare/attributes/local-scope/read-names cases.
A scalar is element 0 of an array for ${x[@]}, ${#x[@]}, ${!x[@]},
${x[0]} and arithmetic element writes. Associative arrays expand in
bash's hash order. [[ -v ]] was missing and is now implemented.
${!ref} resolves a nameref chain, a nameref for-loop variable is
re-pointed per word, and builtin assignment through a circular nameref
fails the command. read takes options only before names, stops at an
invalid name, validates -a names and supports -N.
Unskips 15 bashbox declare/local-scope/read-names cases.
set knows every set -o option and letter, validates before changing anything, lets each o in a cluster take the next argument and lists options for a trailing -o; shopt -o/-po operate on them. $- uses bash's letter order and defaults (hBc). BASH_SUBSHELL counts subshells, command and process substitutions. ( ), [[ ]] and (( )) set PIPESTATUS. The exported environment is snapshotted with subshell state, so (E=2) no longer leaks. local LINENO is an ordinary variable and cd with HOME unset fails. Unskips 12 bashbox attributes/local-scope/shell-variables cases; the remaining declare skips name their reason (printf -v, ANSI-C bytes).
…-eafupr-bb-vars # Conflicts: # THIRD_PARTY_LICENSES/README.md # crates/bashkit/src/builtins/read.rs # crates/bashkit/src/builtins/vars.rs # crates/bashkit/src/interpreter/mod.rs # crates/bashkit/src/parser/lexer.rs # crates/bashkit/tests/spec_cases/bash/bashbox-arithmetic-array.test.sh # crates/bashkit/tests/spec_cases/bash/bashbox-attributes.test.sh # crates/bashkit/tests/spec_cases/bash/bashbox-declare.test.sh # crates/bashkit/tests/spec_cases/bash/bashbox-local-scope.test.sh # crates/bashkit/tests/spec_cases/bash/bashbox-read-names.test.sh # crates/bashkit/tests/spec_cases/bash/bashbox-shell-variables.test.sh # knowledge/log.md
…-eafupr-bb-vars # Conflicts: # crates/bashkit/src/interpreter/mod.rs # crates/bashkit/tests/integration/blackbox_security_tests.rs # knowledge/log.md
Shared by a=(...), a+=(...), declare -a, typeset -a and local -a.
Mixed quoted words like "x"{1,2} expand; keyed assoc values stay
literal; [k]=v{1,2} lexes as one word.
…-eafupr-bb-vars # Conflicts: # crates/bashkit/src/interpreter/mod.rs # knowledge/log.md
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | b5b8196 | Commit Preview URL Branch Preview URL |
Oct 08 2026, 12:12 AM |
A function call is the recursion path. Dispatching it from the same future as the builtin and PATH-search arms put that whole frame on the stack at every call level, so 16 nested calls overflowed a 2 MiB stack in debug builds. Functions now get their own small future, and prefix assignments are boxed. Debug CLI now reaches the depth limit with 1.75 MiB of stack (main needed more than 1.94 MiB).
…-eafupr-bb-vars # Conflicts: # crates/bashkit/src/interpreter/mod.rs # knowledge/log.md
…-eafupr-bb-vars # Conflicts: # knowledge/log.md
…-eafupr-bb-vars # Conflicts: # knowledge/log.md
…-eafupr-bb-vars # Conflicts: # knowledge/log.md
…-eafupr-bb-vars # Conflicts: # knowledge/log.md
chaliy
added a commit
that referenced
this pull request
Oct 8, 2026
The behavior landed with the declaration engine (#2597); these cases pin it: a callee's `unset` uncovers the caller's binding for scalars and arrays, and a local unset in its own scope stays invisible for the rest of the call. Claude-Session: https://claude.ai/code/session_019aFikmptPc91Fj4N2iDXQA
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Михайло · project thread
What changed
declare/typeset/local/readonly/exportnow share one declaration engine that follows bash: attributes (-i -l -u -n -r -x -a -A -g -I) are applied and printed like bash (declare -p,declare -f), locals use bash's dynamic scoping (shallow binding,local -restoring options), and namerefs resolve through scopes.Also in this batch:
$((1/0))abort the line with bash's message.[[ -v name ]],[[ -v a[i] ]], scalars used as arrays (${x[0]}), andreadname validation.set -o/shopt -ooption set,$-in bash order,BASH_SUBSHELLalso counting<(...),PIPESTATUSedge cases, subshell env isolation.a=(x{1,2} *.txt),a+=(...),declare -a/local -a/typeset -a. Quoted words and assoc keyed values stay literal, like bash.Why
Third step of adopting the BashBox corpus (#2575): its bash-verified cases showed declare/local/attribute behavior as the largest gap cluster.
Before / After
BashBox corpus cases still skipped: 420 → 315 (105 unskipped: declare 39, attributes 26, local 20, arithmetic 9, read 8, shell 3).
Comparison against host bash (
LANG=C.UTF-8): only the known environment-specific mismatches remain (read_status_at_eof,empty_heredoc; they depend on the container's/dev/null).Example now passing (was skipped), output matches bash 5.2:
Array literals, new spec cases in
arrays.test.shchecked against host bash:declare -a d=(x{1,2})givesx1 x2.Risk
Interpreter.envis now anArc(copy-on-write, subshells share it), locals use shallow binding.parallel_executionbench: every workload within 3% of main (results incrates/bashkit/benches/results/).tm_dos_060_array_literal_brace_expansion_respects_budget).arr=($v)does not glob split fields yet.Checklist
Generated by Claude Code